package com.wlz.authorization.config;

import com.wlz.authorization.handler.MyAccessDeniedHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 *  Authorization 授权
 *  方法授权
 *     基于注解的访问控制
 *          Spring Security在方法的权限控制上支持三种类型的注解，JSR-250注解、@Secured注解和支持表达式
 *      的注解。这三种注解默认都是没有启用的，需要通过@EnableGlobalMethodSecurity来进行启用。
 *          这些注解可以写到 Service 接口或方法上，也可以写到 Controller或 Controller 的方法上。通常情况下
 *      都是写在控制器方法上的，控制接口URL是否允许被访问。
 *    1. JSR-250注解
 *      @RolesAllowed
 *          表示访问对应方法时所应该具有的角色。其可以标注在类上，也可以标注在方法上，当标注在类上时表
 *      示其中所有方法的执行都需要对应的角色，当标注在方法上表示执行该方法时所需要的角色，当方法和
 *      类上都使用了@RolesAllowed进行标注，则方法上的@RolesAllowed将覆盖类上的@RolesAllowed，即
 *      方法上@RolesAllowed将对当前方法起作用。@RolesAllowed的值是由角色名称组成的数组。
 *      @PermitAll
 *          表示允许所有的角色进行访问，也就是说不进行权限控制。@PermitAll可以标注在方法上也可以标注在
 *      类上，当标注在方法上时则只对对应方法不进行权限控制，而标注在类上时表示对类里面所有的方法都
 *      不进行权限控制。（1）当@PermitAll标注在类上，而@RolesAllowed标注在方法上时则按照
 *      @RolesAllowed将覆盖@PermitAll，即需要@RolesAllowed对应的角色才能访问。
 *          （2）当@RolesAllowed标注在类上，而@PermitAll标注在方法上时则对应的方法也是不进行权限控制的。
 *          （3）当在类和方法上同时使用了@PermitAll和@RolesAllowed时先定义的将发生作用（这个没多大的实际意义，实际应用中不会有这样的定义）。
 *      @DenyAll
 *          是和PermitAll相反的，表示无论什么角色都不能访问。@DenyAll只能定义在方法上。你可能会有疑问
 *      使用@DenyAll标注的方法无论拥有什么权限都不能访问，那还定义它干啥呢？使用@DenyAll定义的方
 *      法只是在我们的权限控制中不能访问，脱离了权限控制还是可以访问的。
 */
//@Configuration
//@EnableGlobalMethodSecurity(jsr250Enabled = true)
//@EnableWebSecurity 基于springboot 可以不用
public class WebSecurityMethodJSR250Config extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin();  //表单登录

        //授权
        http.authorizeRequests()
//                .antMatchers("/admin/demo").permitAll() // 不用认证
                .anyRequest().authenticated();  //  必须认证

        http.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler()); // 支持自定义权限受限处理，需要实现 AccessDeniedHandler接口
        http.csrf().disable();//csrf关掉

    }

    @Bean
    public PasswordEncoder passwordEncoder(){
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }


}
